package com.example.jobback.service.recruiter.impl;

import com.alibaba.fastjson.JSON;
import com.example.jobback.common.enums.PositionStatus;
import com.example.jobback.common.enums.VerifyPublishPositionStatus;
import com.example.jobback.config.AuthConfig;
import com.example.jobback.dto.PublishPositionDto;
import com.example.jobback.dto.UpdatePositionDto;
import com.example.jobback.mapper.CompanyMapper;
import com.example.jobback.mapper.RecruiterMapper;
import com.example.jobback.po.Company;
import com.example.jobback.po.Position;
import com.example.jobback.po.Recruiter;
import com.example.jobback.po.User;
import com.example.jobback.req.common.page.PageReq;
import com.example.jobback.resp.recruiter.common.page.RCrossGetPageRecruiterResp;
import com.example.jobback.resp.recruiter.common.page.RCrossGetPageRecruitersResp;
import com.example.jobback.resp.recruiter.common.seeker.RCrossSeekerMessageResp;
import com.example.jobback.resp.recruiter.position.publish.GetUserPublishPositionResp;
import com.example.jobback.resp.seeker.common.SCrossSeekerResp;
import com.example.jobback.result.Result;
import com.example.jobback.service.common.UserCommonService;
import com.example.jobback.service.recruiter.RecruiterCommonService;
import com.example.jobback.util.CACHEUtil;
import com.example.jobback.util.CrossServiceInvoker;
import com.example.jobback.util.PhoneNumberUtils;
import com.example.jobback.util.TLUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import jakarta.servlet.http.HttpServletResponse;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpMethod;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static com.example.jobback.util.RedisConstants.*;

/**
 * @ClassName: RecruiterCommonServiceImpl
 * @Description:
 * @Author: lhb
 * @Date: 2025/6/24
 */
@Service
public class RecruiterCommonServiceImpl implements RecruiterCommonService {

    private final CACHEUtil cacheUtil;

    @Value("${cross_service_baseurl}")
    private String crossServiceBaseUrl;

    private final AuthConfig authConfig;

    private final RedissonClient redissonClient;

    private final RestTemplate restTemplate;

    private final RecruiterMapper recruiterMapper;


    private final PhoneNumberUtils phoneNumberUtils;


    private final UserCommonService userCommonService;

    private final CompanyMapper companyMapper;

    public RecruiterCommonServiceImpl(CACHEUtil cacheUtil, CompanyMapper companyMapper, RecruiterMapper recruiterMapper, UserCommonService userCommonService, PhoneNumberUtils phoneNumberUtils, AuthConfig authConfig, RestTemplate restTemplate, RedissonClient redissonClient) {
        this.cacheUtil = cacheUtil;
        this.companyMapper = companyMapper;
        this.recruiterMapper = recruiterMapper;
        this.userCommonService = userCommonService;
        this.phoneNumberUtils = phoneNumberUtils;
        this.authConfig = authConfig;
        this.restTemplate = restTemplate;
        this.redissonClient = redissonClient;
    }

    /**
     * @Description: 获取公司信息
     * @param companyId 
     * @return Company
     * @Author lhb
     * @CreateTime 2025/6/24 21:00
     */
    @Override
    public Company getCompanyMessage(Long companyId) {
        String key = COMPANY_KEY + companyId.toString();
        // 尝试从缓存获取数据
        Map<Object, Object> companyMap = cacheUtil.getHash(key);
        String companyJson = (String) companyMap.get(COMPANY_KEY_FIELD_COM);
        Company company = JSON.parseObject(companyJson, Company.class);
        // 缓存命中，直接返回
        if (company != null) {
            return company;
        }
        // 缓存未命中，检查是否是缓存穿透的空值标记
        if (companyMap.containsKey(COMPANY_KEY_FIELD_NULL) && COMPANY_KEY_NULL_VALUE.equals(companyMap.get(COMPANY_KEY_FIELD_NULL))) {
            return null;
        }
        // 使用Redisson的锁
        RLock lock = redissonClient.getLock(LOCK_COMPANY_KEY+companyId);
        boolean locked = false;
        try {
            // 获取分布式锁
            locked = lock.tryLock(3, 10, TimeUnit.SECONDS);
            if (locked) {
                // 双重检查缓存，防止锁等待期间已有线程更新了缓存
                companyMap = cacheUtil.getHash(key);
                companyJson = (String) companyMap.get(COMPANY_KEY_FIELD_COM);
                company = JSON.parseObject(companyJson, Company.class);
                if (company != null) {
                    return company;
                }
                // 缓存穿透标记检查
                if (companyMap.containsKey(COMPANY_KEY_FIELD_NULL) && COMPANY_KEY_NULL_VALUE.equals(companyMap.get(COMPANY_KEY_FIELD_NULL))) {
                    return null;
                }
                // 查询数据库
                company = companyMapper.getCompanyById(companyId);

                // 构建缓存数据
                Map<String, Object> companyData = new HashMap<>();
                if (company == null) {
                    // 处理缓存穿透：缓存空值，设置较短过期时间
                    companyData.put(COMPANY_KEY_FIELD_NULL, COMPANY_KEY_NULL_VALUE);
                    // 空值缓存时间设短一些，比如5分钟
                    cacheUtil.setHash(key, companyData, COMPANY_TTL, TimeUnit.MINUTES);
                } else {
                    // 正常数据缓存
                    String companyStoreJson = JSON.toJSONString(company);
                    companyData.put(COMPANY_KEY_FIELD_COM, companyStoreJson);
                    cacheUtil.setHash(key, companyData, COMPANY_TTL, TimeUnit.HOURS);
                }
                return company;
            } else {
                // 等待
                Thread.sleep(100);
                // 递归重试
                return getCompanyMessage(companyId);
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            return null;
        } finally {
            // 释放锁
            if (locked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * @Description: 批量获取公司信息
     * @param companyIds
     * @return List<Company>
     * @Author lhb
     * @CreateTime 2025/7/25 10:03
     */
    @Override
    public List<Company> getCompanyMessagesByIds(List<Long> companyIds) {
        List<Company> companyList = new ArrayList<>();
        for (Long companyId : companyIds) {
            Company company = getCompanyMessage(companyId);
            companyList.add(company);
        }
        return companyList;
    }


    /**
     * @Description: 分页获取招聘者列表，被调用方
     * @param pageReq
     * @return Result<RCrossGetPageRecruitersResp>
     * @Author lhb
     * @CreateTime 2025/7/4 15:26
     */
    @Override
    public Result<RCrossGetPageRecruitersResp> getRecruiters(PageReq pageReq) {
        String content=pageReq.getContent();
        int size = pageReq.getSize();
        int page = pageReq.getPage();
        if(content.isEmpty()){
            PageHelper.startPage(page, size);
            List<Recruiter> recruiters=recruiterMapper.getRecruiters();
            //获取页的相关信息
            PageInfo<Recruiter> recruiterPageInfo = new PageInfo<>(recruiters);
            //获取userid查找user对象
            List<Long> userIds = recruiters.stream()
                    .map(Recruiter::getUserId)
                    .filter(Objects::nonNull)
                    .toList();
            List<User> users=userCommonService.getUsersByUserIds(userIds);
            //处理分页查询管理员列表响应体
            RCrossGetPageRecruitersResp resp=processPageRecruiterList(recruiters,users,recruiterPageInfo);
            return Result.success(resp);
        }
        List<User> users=userCommonService.getUsersByName(content);
        if(users.isEmpty()){
            RCrossGetPageRecruitersResp resp = new RCrossGetPageRecruitersResp();
            resp.setPages(0);
            resp.setTotal(0L);
            resp.setPageNum(0);
            resp.setPageSize(0);
            resp.setSize(0);
            resp.setRespList(new ArrayList<>());
            return Result.success(resp);
        }
        List<Long> userIds = users.stream()
                .map(User::getUserId)
                .filter(Objects::nonNull)
                .toList();
        PageHelper.startPage(page, size);
        List<Recruiter> recruiters=recruiterMapper.getRecruiterByUserIds(userIds);
        //获取页的相关信息
        PageInfo<Recruiter> recruiterPageInfo = new PageInfo<>(recruiters);
        //处理分页查询管理员列表响应体
        RCrossGetPageRecruitersResp resp=processPageRecruiterList(recruiters,users,recruiterPageInfo);
        return Result.success(resp);
    }

    /**
     * @Description: 跨服务调用，获取求职者基本信息
     * @param userId
     * @return Result<RCrossSeekerMessageResp>
     * @Author lhb
     * @CreateTime 2025/7/3 21:53
     */
    @Override
    public Result<RCrossSeekerMessageResp> getSeekerBasicMessage(Long userId) {
        Map<String, Object> params = new HashMap<>();
        params.put("userId", userId);
        String url = crossServiceBaseUrl + "/seeker/common/getSeekerBasicMessage";
        // 手动创建 CrossServiceInvoker 实例
        CrossServiceInvoker invoker =
                new CrossServiceInvoker(authConfig, restTemplate);
        Result<SCrossSeekerResp> result = null;
        try {
            result = invoker.invokeAndHandle(
                    url,
                    HttpMethod.POST,
                    null,
                    SCrossSeekerResp.class,
                    userId,
                    params
            );
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        if(!result.getCode().equals(HttpServletResponse.SC_CREATED)) {
            throw new IllegalArgumentException("VALIDATION_ERROR：无此用户招聘端信息");
        }
        RCrossSeekerMessageResp resp=new RCrossSeekerMessageResp();
        BeanUtils.copyProperties(result.getData(), resp);
        return Result.success(resp);
    }

    /**
     * @Description: 根据userId删除用户发布中的岗位
     * @param deleteUserId
     * @return void
     * @Author lhb
     * @CreateTime 2025/7/27 16:03
     */
    @Override
    public void deleteRecruiterPubPositionsRedis(Long deleteUserId, Long deleteRecruiterCompanyId) {
        //获取code集合
        Set<String> codesByRank = cacheUtil.getMembersByRank(
                VERIFY_RECRUITER_PUBLISH_POSITION_RECRUITER_CODE_KEY+deleteUserId, 0, -1);
        if(codesByRank.isEmpty()) {
            //无正在发布的岗位，退出
            return;
        }
        //recruiter-code
        cacheUtil.deleteKeySafely(VERIFY_RECRUITER_PUBLISH_POSITION_RECRUITER_CODE_KEY+deleteUserId);
        for (String code : codesByRank) {
            //manager-code
            cacheUtil.removeMember(VERIFY_RECRUITER_PUBLISH_POSITION_MANAGER_CODE_KEY,code);
            //com-code
            cacheUtil.removeMember(VERIFY_RECRUITER_PUBLISH_POSITION_COM_CODE_KEY+deleteRecruiterCompanyId,code);
            //删除职位信息redis记录
            cacheUtil.deleteKeySafely(VERIFY_RECRUITER_PUBLISH_POSITION_KEY+code);
        }
    }

    /**
     * @Description: 根据userId删除岗位变更数据
     * @param deleteUserId
     * @param deleteRecruiterCompanyId 
     * @return void
     * @Author lhb
     * @CreateTime 2025/7/27 21:47
     */
    @Override
    public void deleteRecruiterUpdatePositionsRedis(Long deleteUserId, Long deleteRecruiterCompanyId) {

        //获取code集合
        Set<String> positionIdSet = cacheUtil.getMembersByRank(
                VERIFY_RECRUITER_UPDATE_POSITION_RECRUITER_ID_KEY+deleteUserId, 0, -1);
        if(positionIdSet.isEmpty()) {
            //无正在发布的岗位，退出
            return;
        }
        //recruiter
        cacheUtil.deleteKeySafely(VERIFY_RECRUITER_UPDATE_POSITION_RECRUITER_ID_KEY+deleteUserId);

        for (String positionId : positionIdSet) {
            //manager
            cacheUtil.removeMember(VERIFY_RECRUITER_UPDATE_POSITION_MANAGER_ID_KEY,positionId);
            //com-code
            cacheUtil.removeMember(VERIFY_RECRUITER_UPDATE_POSITION_COM_ID_KEY+deleteRecruiterCompanyId,positionId);
            //删除职位信息redis记录
            cacheUtil.deleteKeySafely(VERIFY_RECRUITER_UPDATE_POSITION_KEY+positionId);
        }
    }

    /**
     * @Description: 使用stream.map等处理分页查询招聘者列表响应体
     * @param recruiters
     * @param users
     * @param recruiterPageInfo 
     * @return RCrossGetPageRecruitersResp
     * @Author lhb
     * @CreateTime 2025/7/3 17:18
     */
    private RCrossGetPageRecruitersResp processPageRecruiterList(List<Recruiter> recruiters,
                                                                 List<User> users,
                                                                 PageInfo<Recruiter> recruiterPageInfo) {
        //初始化响应体
        RCrossGetPageRecruitersResp resp=new RCrossGetPageRecruitersResp();
        resp.setRespList(new ArrayList<>());
        // 使用 Stream 和 map 方法进行映射
        List<Recruiter> mappedRecruiters = recruiters.stream()
                .map(recruiter -> {
                    // 找到对应的 User
                    users.stream()
                            .filter(u -> u.getUserId().equals(recruiter.getUserId()))
                            .findFirst().ifPresent(user -> BeanUtils.copyProperties(user, recruiter));
                    return recruiter;
                })
                .toList();
        //构造响应体
        resp.setPages(recruiterPageInfo.getPages());
        resp.setTotal(recruiterPageInfo.getTotal());
        resp.setPageNum(recruiterPageInfo.getPageNum());
        resp.setPageSize(recruiterPageInfo.getPageSize());
        resp.setSize(recruiterPageInfo.getSize());
        List<Recruiter> pageRecruiterList=recruiterPageInfo.getList();
        for (Recruiter recruiter:pageRecruiterList){
            String phone="";
            try {
                phone=phoneNumberUtils.decryptPhone(recruiter.getPhoneAes());
            } catch (Exception e) {
                throw new RuntimeException("电话号码格式有误，解密失败");
            }
            RCrossGetPageRecruiterResp recruiterResp=new RCrossGetPageRecruiterResp();
            BeanUtils.copyProperties(recruiter,recruiterResp);
            recruiterResp.setPhone(phone);
            resp.getRespList().add(recruiterResp);
        }
        return resp;
    }
}
